home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
asmutil
/
asm_n_z.zip
/
OVLMGR.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-11-27
|
31KB
|
1,180 lines
; SCCS Id: @(#)ovlmgr.asm 3.0 89/11/16
; Copyright (c) Pierre Martineau and Stephen Spackman, 1989.
; This product may be freely redistributed. See NetHack license for details.
PAGE 60,132
TITLE 'Overlay manager for use with Microsoft overlay linker'
SUBTTL 'Brought to you by Pierre Martineau and Stephen Spackman'
; acknowledgements: - No thanks to Microsoft
; - alltrsidsctysti!!!
; - izchak and friends for impetus
; - us for brilliance
; - coffee for speed
; - others as necessary
; assumptions: - all registers are preserved including flags
; - the stack is preserved
; - re-entrancy is not required
DOSALLOC equ 48h ; memory allocation
DOSFREE equ 49h ; free allocated memory
DOSREALLOC equ 4ah ; modify memory block
DOSREAD equ 3fh ; read bytes from handle
DOSSEEK equ 42h ; logical handle seek
DOSOPEN equ 3dh ; open handle
DOSCLOSE equ 3eh ; close handle
DOSGETVEC equ 35h ; get interrupt vector
DOSSETVEC equ 25h ; set interrupt vector
DOSEXEC equ 4bh ; exec child process
DOS equ 21h ; Dos interrupt #
PRINT equ 09h ; print string
TERMINATE equ 4ch ; terminate process
CR equ 0dh
LF equ 0ah
BELL equ 07h
FAERIE equ 0h ; Used for dummy segment allocation
PARSIZ equ 10h ; this is the size of a paragraph - this better not change!
; The following extrns are supplied by the linker
extrn $$OVLBASE:byte ; segment of OVERLAY_AREA
extrn $$MPGSNOVL:byte ; ^ to module table
extrn $$MPGSNBASE:word ; ^ to module segment fixups
extrn $$INTNO:byte ; interrupt number to be used
extrn $$COVL:word ; number of physical overlays
extrn $$CGSN:word ; number of modules
extrn $$MAIN:far ; ^ to function main()
public $$OVLINIT ; Our entry point
; called by the c startup code
ovlflgrec record running:1=0,locked:1=0,loaded:1=0 ; overlay flags
; This is a dirty hack. What we need is a virtual segment that will be built
; by the (our) loader in multiple copies, one per overlay. Unfortunately, this
; doesn't seem to be a sensible idea in the minds of the folks at Microsoft.
; Declaring this segment AT will ensure that it never appears in the exefile,
; and ASSUME is dumb enough to be fooled.
;
; The reason we want to do this is also not-to-be-tried-at-home: it turns out
; that we can code a faster interrupt handler if we map overlay numbers to
; segment values. Normally I would consider this unacceptable programming
; practise because it is 86-mode specific, but the *need* for this entire
; programme is 86-mode specific, anyway.
pspseg segment para at FAERIE ; dummy segment for psp
org 2ch ; ^ to segment of environmemt in psp
pspenv LABEL WORD
pspseg ends
ovltbl segment para at FAERIE ; Dummy segment definition for overlay table
; NOTE: This segment definition MUST be exactly 16 bytes long
ovlflg ovlflgrec <0,0,0> ; overlay flags
ovltblpad1 db ? ; go ahead, delete me!
ovlmemblk dw ? ; ^ to allocated memory block
ovlseg dw 0 ; ovl segment physical add.
ovlfiloff dw ? ; ovl file offset in pages (512 bytes)
ovlsiz dw ? ; ovl size in paragraphs
ovllrudat dd 0 ; misc lru data (pseudo time stamp)
ovltblpad2 dw ? ; go ahead, delete me!
if1
if $ gt PARSIZ
.err
%out This segment MUST be no more than 16 bytes, REALLY!!!
endif
endif
ovlsegsiz equ PARSIZ ; this had better be true!!! (16 bytes)
ovltbl ends
EXEHDR struc ; structure of an EXE header
exesign dw 5a4dh ; signature
exelstpgesiz dw ? ; last page size (512 byte pages)
exesiz dw ? ; total pages (including partial last page)
relocitems dw ? ; number of relocation entries
hdrparas dw ? ; number of paragraphs in the header
minalloc dw ? ; minimum paragraph allocation
maxalloc dw ? ; maximum patagraph allocation
exess dw ? ; initial stack segment
exesp dw ? ; initial stack pointer
exechksum dw ? ; checksum
exeip dw ? ; initial instruction pointer
execs dw ? ; initial code segment
reloctbloff dw ? ; offset from beginning of header to relocation table
exeovlnum dw ? ; overlay number
EXEHDR ends
MASK_used equ 1 ; memory block flag
memctlblk struc ; memory block structure
memblkflg db 0 ; flags
memblkpad1 db 0 ; go ahead, delete me!
memblknxt dw 0 ; ^ to next block
memblkprv dw 0 ; ^ to previous block
memblkovl dw 0 ; ^ to overlay occupying this block
memblksiz dw 0 ; size in paragraphs
memblkpad db PARSIZ - ($ - memblkflg) mod parsiz dup (?) ; pad to 16 bytes
memctlblk ends
memctlblksiz equ memblkpad + SIZE memblkpad ; should equal 1 paragraph (16 bytes)
;-------------------------------------------------------------------------------
code segment public
ovlexefilhdl dw -1 ; always-open file handle of our .EXE
ovltim dd 0 ; pseudo-lru time variable
curovl dw offset framestk ; ^ into stack frame
ovlcnt dw 0 ; # overlays
modcnt dw 0 ; # of modules
ovltblbse dw -1 ; segment of first overlay descriptor
ovlrootcode dw 0 ; logical segment of OVERLAY_AREA
ovldata dw 0 ; logical segment of OVERLAY_END
memblk1st dw 0 ; first memory block
pspadd dw 0 ; our psp address + 10h (for relocations)
oldvec dd -1 ; saved interrupt vector
oldint21 dd -1 ; saved int 21 vector
memstat db 0ffh ; must we re-allocate some memory
bxreg dw 0 ; temp save area
esreg dw 0 ; temp save area
farcall dd 0 ; internal trampoline.
hdr EXEHDR <> ; EXE header work area
hdrsize equ $ - hdr
framestk dw 100h dup (0) ; internal stack
moduletbl dw 256*2 dup (0) ; module lookup table
noroom db CR,LF,'Not enough memory to run this program. Time to go to the store.',CR,LF,BELL,'$'
nocore db CR,LF,'Your dog eats all your remaining memory! You die.',CR,LF,BELL,'$'
nofile db CR,LF,'The Nymph stole your .EXE file! You die.',CR,LF,BELL,'$'
exitmsg db CR,LF,'$'
;-------------------------------------------------------------------------------
$$OVLINIT proc far ; Init entry point
assume cs:code,ds:pspseg,es:nothing
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es ; save the world
mov ax,ds ; get our psp
add ax,10h
mov pspadd,ax ; save it
mov ds,pspenv ; get environment segment
mov si,-1
envloop: ; search for end of environment
inc si
cmp word ptr [si],0
jnz envloop
add si,4 ; point to EXE filename
mov al,0 ; access code
mov ah,DOSOPEN
mov dx,si
int DOS ; open EXE
jnc dontdie
mov al,5
mov dx,offset nofile
jmp putserr ; cry to the world!
dontdie:
mov ovlexefilhdl,ax ; save handle
mov ax,SEG $$OVLBASE ; OVERLAY_AREA segment
mov ovlrootcode,ax
; Now allocate memory
mov bx,0900h ; allocate memory for malloc()
mov ah,DOSALLOC
int DOS
jnc getmore
jmp buyram
getmore:
mov es,ax ; find largest free memory
mov ah,DOSALLOC
mov bx,0ffffh ; Everything
int DOS
mov ah,DOSALLOC ; allocate our own memory
int DOS
jnc gotitall
jmp buyram
gotitall:
mov memstat,0 ; indicate that we have memory
mov ovltblbse,ax ; overlay descriptor table begins at start of memory block
mov ax,SEG $$COVL ; segment of DGROUP
mov ds,ax
mov cx,$$CGSN ; number of modules
mov modcnt,cx ; save for later use
mov cx,$$COVL ; number of physical overlays
mov ovlcnt,cx ; save for later use
sub bx,cx ; enough mem for ovl tbl?
jnc memloop
jmp buyram
memloop:
push bx
mov ah,DOSFREE ; free first block for malloc()
int DOS
jnc cockadoodledoo
jmp buyram
cockadoodledoo:
assume es:ovltbl
xor bp,bp
xor di,di
xor si,si
filsegtbllpp: ; initialise ovl table
call gethdr ; get an EXE header
mov ax,ovltblbse
add ax,hdr.exeovlnum
mov es,ax ; ^ to ovl table entry
xor ax,ax
mov word ptr ovllrudat,ax ; initialise ovl lru
mov word ptr ovllrudat+2,ax
mov ovlseg,ax ; initialise ovl segment
mov ovlflg,al ; initialise ovl flags
mov ax,hdr.exesiz
shl ax,1
shl ax,1
shl ax,1
shl ax,1
shl ax,1 ; * 32
mov dx,hdr.exelstpgesiz
or dx,dx
jz emptypage
shr dx,1
shr dx,1
shr dx,1
shr dx,1 ; / 16
inc dx
sub ax,20h
add ax,dx
emptypage:
mov ovlsiz,ax ; overlay size in paragraphs
sub ax,hdr.hdrparas ; actual size of